#include "../lib/useHead.h"
#include "../lib/stringtable.h"
#include "../lib/functable.h"
#include "../lib/instrStream.h"
#include "../lib/scriptHead.h"
#include "../lib/labelTable.h"
#include "../lib/symTable.h"
#include "../lib/script.h"
#include "vm.h"

void   RunTimeStack::reset(int size)
{
	_topIndex = 0;
	_frameIndex = 0;
	_data.resize(size);
	for (int i = 0; i < size; ++i) {
		_data[i]._type = OP_FLAG_TYPE_NULL;
	}
}


bool   RunTimeStack::indexCheck(int index)
{
	if (index < 0 || index > _topIndex) 
		return false;

	return true;
}


Value  RunTimeStack::pop()
{
	if (--_topIndex < 0) {
		printf("RunTimeStack is empty!");
		return _data[0];
	}

	return _data[_topIndex];
}


void   RunTimeStack::push(Value &val)
{
	_data[_topIndex++] = val;
}


void   RunTimeStack::setStackValue(int index, Value &value)
{
	if (index < 0) 
		index += _frameIndex;

	if (!indexCheck(index)) {
	       	printf("Index out of range: index %d, size %d\n", index, _data.size());
		return ;
 	}		

	_data[index] = value;

}


Value &RunTimeStack::getStackValue(int index)
{
	if (index < 0) 
		index += _frameIndex;

	if (!indexCheck(index)) {
	       	printf("Index out of range: index %d, size %d\n", index, _data.size());
		return _data[_topIndex-1];
 	}		

	return _data[index];
}
	

void RunTimeStack::popFrame(int size)
{
	_topIndex -= size;
	if (_topIndex < 0) {
		printf("RunTimeStack pop Frame error!\n");
		_topIndex = 0;
	}
}


void RunTimeStack::pushFrame(int size)
{
	if (size < 0) {
		printf("RunTimeStack push a negative size\n");
		return;
	}

	_topIndex += size;
	_frameIndex = _topIndex;
}



OpType RunScript::resolveOpType(int index)
{
	Value &val = resolveOpValue(index);
	return val._type;
}


Value  &RunScript::resolveOpValue(int index)
{
	Instr &instr = _is.getInstruction(_state._currInstr);
	Value &val = instr._valList[index]; 
	
	if (val._type == OP_FLAG_TYPE_ABS_STACK_INDEX)	
			return _stack.getStackValue(val._vindex);
    else if (val._type == OP_FLAG_TYPE_REL_STACK_INDEX) {
			Value &tval = _stack.getStackValue(val._offset);
			return _stack.getStackValue(val._vindex + tval._vint);
    } else if (val._type == OP_FLAG_TYPE_REG)
			return _state._retVal;
    else 
			return val;
}


int   RunScript::__Int(Value &val)
{
    switch(val._type) {
		case OP_FLAG_TYPE_INSTR_INDEX:
			return val._vindex;
		case OP_FLAG_TYPE_INT:
			return val._vint;
		case OP_FLAG_TYPE_FLOAT:
			return (int)val._vfloat;
		case OP_FLAG_TYPE_STRING:
			return atoi(val._svalue.c_str());
		default:
			return 0;
	}
}
    

float   RunScript::__Float(Value &val)
{
    switch(val._type) {
		case OP_FLAG_TYPE_INT:
			return (float)val._vint;
		case OP_FLAG_TYPE_FLOAT:
			return val._vfloat;
		case OP_FLAG_TYPE_STRING:
			return atof(val._svalue.c_str());
		default:
			return 0.0;
	}
}
    

string &   RunScript::__String(Value &val)
{
    static char   buf[16];
	static string s;

	switch(val._type) {
		case OP_FLAG_TYPE_INT:
			sprintf(buf, "%d", val._vint);
			s = buf;
			return s;
		case OP_FLAG_TYPE_FLOAT:
			sprintf(buf, "%f", val._vfloat);
			s = buf;
			return s;
		case OP_FLAG_TYPE_STRING:
			return val._svalue;
		default:
			s = "";
			return s;
	}
}


int   RunScript::_Int(int index)
{
	Value &val = resolveOpValue(index);
	return __Int(val);
}


float RunScript::_Float(int index)
{
	Value &val = resolveOpValue(index);
	return __Float(val);
}



string &RunScript::_String(int index)
{
	Value &val = resolveOpValue(index);
	return __String(val);
}


void RunScript::reset()
{
	_state._pauseT = 0;
	_state._isActive = false;
	_state._isRunning = false;
	_state._currInstr = -1;	
	_state._retVal._type = OP_FLAG_TYPE_NULL;
	
	int stackSize = _sh._sh._stackSize;
	if (stackSize <= 0)
		stackSize = DEFAULT_STACK_SIZE;

	_stack.reset(stackSize);
}

void RunScript::run()
{
    while (_state._isActive && _state._isRunning)
        RunOneInstr();
}


void RunScript::RunOneInstr()
{
	clock_t now;

	if (!_state._isActive || !_state._isRunning)
		return;

	int instr_index = _state._currInstr;
	if (instr_index < 0) {
		_state._isRunning = false;
		return;
	}

	Instr &instr = _is.getInstruction(_state._currInstr);		
	if (!_exec(*this, instr)) {
		_exec.errorInfo();
	}

	if (instr_index == _state._currInstr)
		++_state._currInstr;
}


bool RunScript::callFunc(int index)
{
    int ep = _ft.getEntryPoint(index);
    if (ep < 0) 
        return false;

    int frameIndex = _stack.getFrame();

    Value ret;
    ret._type = OP_FLAG_TYPE_KEY_FRAME;
    ret._vindex = _state._currInstr;
    _stack.push(ret);

    _stack.pushFrame(funcSize(index)+1);
    
    ret._type = OP_FLAG_TYPE_TOP_FRAME;
    ret._vindex = index;
    ret._offset = frameIndex;
    
    Value &top = _stack.getTopValue();
    top = ret;
    
    jump(ep);
    _stack.align();
    return true;
}


FILE_ERROR_TYPE  RunScript::readFile(const char *name)
{
    FILE_ERROR_TYPE ret;

    if ((ret = TScript::readFile(name)) == E_SUCCESS) {
        _state._isActive = true;
        //printf("set Active flag!\n");
        _stack.pushFrame(_sh._sh._globalDataSize);

        if (_sh._sh._mainIndex != -1) {
            //printf("main present, set running flag!\n");
	        _state._isRunning = true;
            callFunc(_sh._sh._mainIndex);
            //printf("push frame size: %d", _ft.getlocalDataSize(_sh._sh._mainIndex));
            _state._currInstr = _ft.getEntryPoint(_sh._sh._mainIndex);
            //printf("set PI %d", _state._currInstr);
	    }
	}

    return ret;
}


void RunScript::showInfo(char *info)
{
    char buf[80];
    
    snprintf(buf, sizeof(buf), "<PI %d>\n",  _state._currInstr);
    strcat(info, buf);

    snprintf(buf, sizeof(buf), "<Sk %d> ", _sh._sh._stackSize);
    strcat(info, buf);

    snprintf(buf, sizeof(buf), "<MI %d>\n", _sh._sh._mainIndex);
    strcat(info, buf);

    snprintf(buf, sizeof(buf), "<GDS %d>\n\n", _sh._sh._globalDataSize);
    strcat(info, buf);

    strcat(info, "Stack Info:\n");
    snprintf(buf, sizeof(buf), "<S %d> ",  _stack.size());
    strcat(info, buf);

    snprintf(buf, sizeof(buf), "<T %d> ",  _stack.getTop());
    strcat(info, buf);

    snprintf(buf, sizeof(buf), "<F %d>\n", _stack.getFrame());
    strcat(info, buf);

    strcat(info, "Register!\n");
    strcat(info, InstrStream::valueDump(_state._retVal));
}


int   RunScript::PInt(int paramIndex)
{
    ++paramIndex;
    Value &val = _stack.getStackValue(_stack.getTop() - paramIndex);
    
    return __Int(val);
}


float RunScript::PFloat(int paramIndex)
{
    ++paramIndex;
    Value &val = _stack.getStackValue(_stack.getTop() - paramIndex);

    return  __Float(val);
}


string &RunScript::PString(int paramIndex)
{
    ++paramIndex;
    Value &val = _stack.getStackValue(_stack.getTop() - paramIndex);

    return __String(val);
}


bool    RunScript::callHostFunc(int index)
{
    bool ret;
    string name = _hst.getIndex(index);

    T_HAF &apiStruct = _exec.getAPIFunc(name);

    if (apiStruct._apiFunc == NULL) 
        ret = false;
    else {
        ret = (apiStruct._apiFunc)(*this);
    }

    _stack.popFrame(apiStruct._params);
   
    return ret;
}


void RunScript::returnInt(int i)
{
    _state._retVal._type = OP_FLAG_TYPE_INT;
    _state._retVal._vint = i;
}


void RunScript::returnFloat(float i)
{
    _state._retVal._type = OP_FLAG_TYPE_FLOAT;
    _state._retVal._vfloat = i;
}


void RunScript::returnString(const string &str)
{
    _state._retVal._type = OP_FLAG_TYPE_STRING;
    _state._retVal._svalue = str;
}


void Execute::errorInfo()
{
	printf("Error: %s\n", _error);
}


bool Execute::regist(CODE code, instr_func func)
{
	INSTR_MAP::iterator Iter = _instr_func_map.find(code);
	if (Iter != _instr_func_map.end()) {
		snprintf(_error, sizeof(_error), "Func for Code %d already exist!", code);
		return false;
	}

	_instr_func_map[code] = func;
	return true;
}


bool Execute::registRegStruct(RegStruct reg[])
{
    int i = 0;
    while (1) {
        if (reg[i]._fname == NULL)
            break;
        if (!registHostAPIFunc(reg[i]._fname, reg[i]._func, reg[i]._fparam)) {
            fprintf(stderr, "regist Func %s Failed!\n", reg[i]._fname);
        }
        ++i;
    }

    return true;
}   
    

bool Execute::operator()(RunScript &rs, Instr &is)
{
	INSTR_MAP::iterator Iter = _instr_func_map.find(is._opCode);
	if (Iter == _instr_func_map.end()) {
		snprintf(_error, sizeof(_error), "Code %d not exist!", is._opCode);
		return false;
	}

	instr_func func = Iter->second;
	if (func == NULL) {
		snprintf(_error, sizeof(_error), "Func for Code %d is NULL!", is._opCode);
		return false;
	}

	return func(rs, is, _error);
}


bool Execute::registHostAPIFunc(const string &name, HostApiFunc func, int params)
{   
    API_MAP::iterator Iter = _api_map.find(name);
    if (Iter != _api_map.end()){
        snprintf(_error, sizeof(_error), "API Func %s already exist!", name.c_str());
        return false;
    }

    T_HAF t = {func, params};
    _api_map[name] = t;
    return true;
}


T_HAF &Execute::getAPIFunc(const string &name)
{
    static T_HAF HAF_NULL = {NULL, 0};

    API_MAP::iterator Iter = _api_map.find(name);
    if (Iter != _api_map.end()) {
        return Iter->second;
    }

    return HAF_NULL;
}
